package com.mingyuean.demo.mybatis.parameter;

/**
 * @author MingYueAn
 * <p>  通用令牌分析器
 * <p>  2023/3/12 17:15
 * @version: 1.0
 */
public class GenericTokenParser {

    /**
     * 开始的标记
     */
    private final String openToken;
    /**
     * 结束的标记
     */
    private final String closeToken;
    /**
     * 处理器
     */
    private final TokenHandler tokenHandler;

    /**
     * 构造器
     *
     * @param openToken    开始标记
     * @param closeToken   结束标记
     * @param tokenHandler 处理器
     */
    public GenericTokenParser(String openToken, String closeToken, TokenHandler tokenHandler) {
        this.openToken = openToken;
        this.closeToken = closeToken;
        this.tokenHandler = tokenHandler;
    }

    /**
     * 解析SQL语句
     *
     * @param sql
     * @return
     */
    public String parse(String sql) {
        final StringBuilder stringBuilder = new StringBuilder();
        // 判断传过来的sql语句是否为null或""
        if (sql != null && sql.length() > 0) {
            //将sql语句转换为char数组
            final char[] sqlChar = sql.toCharArray();
            int offset = 0;
            //获取"#{"第一次出现的位置
            //返回某个指定的字符串值在字符串中首次出现的位置
            int start = sql.indexOf(openToken, offset);
            while (start > -1) {
                if (sqlChar[start - 1] == '\\') {
                    stringBuilder.append(sqlChar, offset, start - offset - 1).append(openToken);
                    offset = start + openToken.length();
                } else {
                    int end = sql.indexOf(closeToken, start);
                    if (end == -1) {
                        stringBuilder.append(sqlChar, offset, sqlChar.length - offset);
                        offset = sqlChar.length;
                    } else {
                        stringBuilder.append(sqlChar, offset, start - offset);
                        offset = start + openToken.length();
                        // 获取#{id}中的id
                        String content = new String(sqlChar, offset, end - offset);
                        // 得到一对大括号里的字符串后，调用handler.handleToken,比如替换变量这种功能
                        stringBuilder.append(tokenHandler.handleToken(content));
                        offset = end + closeToken.length();
                    }
                }
                start = sql.indexOf(openToken, offset);
            }
            if (offset < sqlChar.length) {
                stringBuilder.append(sqlChar, offset, sqlChar.length - offset);
            }
        }
        return stringBuilder.toString();
    }

}
